#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QtDebug>
#include <Ice/Ice.h>
#include <ObjIdentify.h>
#include <QMessageBox>
#include <QPen>
#include <QFont>
#include <QPainter>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    kModelWidth = 224;
    kModelHeight = 224;
    chn =3;
    deviceID =0;


    for(int i=0; i<4 ; i++){
        workThread[i] = new WorkThread(this);
        QObject::connect(workThread[i], SIGNAL(send_output_text(QString,QString)), this ,SLOT(showResult(QString,QString)));
        QObject::connect(this, SIGNAL(sendFlagToWorkThread(bool , int, QString)), workThread[i] ,SLOT(setFlag(bool , int, QString)));

    }
    map.insert("0","零");
    map.insert("1","一");
    map.insert("2","二");
    map.insert("3","三");
    map.insert("4","四");
    map.insert("5","五");
    map.insert("radar","radar");
    map.insert("burke","burke");
    map.insert("ticonderoga","ticonderoga");
    map.insert("bridge","bridge");
    map.insert("wasp","wasp");
    map.insert("freedom","freedom");
    map.insert("nimitz","nimitz");


    setWindowFlags(Qt::FramelessWindowHint);
    setWindowState(Qt::WindowMaximized);
    timer = new QTimer(this);
    connect(timer,SIGNAL(timeout()), this, SLOT(showTime()));
    timer->start(1000);
    showTime();
    readXml("platform.xml");

    connect(ui->rb200dk,SIGNAL(toggled(bool)),this,SLOT(checkrb(bool)));
    connect(ui->rbFpga,SIGNAL(toggled(bool)),this,SLOT(checkrb(bool)));
    connect(ui->rbArm,SIGNAL(toggled(bool)),this,SLOT(checkrb(bool)));
    connect(ui->rbNvidia,SIGNAL(toggled(bool)),this,SLOT(checkrb(bool)));

}

MainWindow::~MainWindow()
{
    delete ui;
}


ComputingPlatform MainWindow::getComputingPlatform()
{
    if(ui->rb200dk->isChecked())
        return DK200;
    if(ui->rbFpga->isChecked())
        return FPGA;
    if(ui->rbArm->isChecked())
        return ARM;
    if(ui->rbNvidia->isChecked())
        return NVIDIA;
}


int MainWindow::getProcessType(){

    if(ui->rbClassify->isChecked())
        return 2;
    if(ui->rbDetection->isChecked())
        return 3;
    if(ui->rbHandDetect->isChecked())
        return 1;
}



void MainWindow::showMsg(QString msg, int num)
{

    switch (num) {
        case 1:ui->lbResult->setText(msg);break;
        case 2:ui->lbResult_2->setText(msg);break;
        case 3:ui->lbResult_3->setText(msg);break;
        case 4:ui->lbResult_4->setText(msg);break;
    }
}

void MainWindow::showTime()
{
    time = QTime::currentTime();
    QString timeStr = time.toString("hh:mm:ss");
    ui->lcdTime->display(timeStr);

}

void MainWindow::on_tbMixWindows_clicked()
{
    setWindowState(Qt::WindowMinimized);
}

void MainWindow::on_tbMaxWindows_clicked()
{
    setWindowState(Qt::WindowMaximized);
}
void MainWindow::on_close_clicked()
{


    emit sendFlagToWorkThread(true,2,"thread0");
    emit sendFlagToWorkThread(false,1,"thread0");
    emit sendFlagToWorkThread(true,2,"thread1");
    emit sendFlagToWorkThread(false,1,"thread1");
    emit sendFlagToWorkThread(true,2,"thread2");
    emit sendFlagToWorkThread(false,1,"thread2");
    emit sendFlagToWorkThread(true,2,"thread3");
    emit sendFlagToWorkThread(false,1,"thread3");

    for(int i=0; i<4 ; i++){
        workThread[i]->wait();
    }
    close();
}

QStringList MainWindow::getFileNames(const QString &path)
{
    QDir dir(path);
    QStringList nameFilters;
    nameFilters << "*.jpg" << "*.png";
    QStringList files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name);
    return files;
}

void MainWindow::on_pbOpenDir_clicked()
{
    QString directoryName = QFileDialog::getExistingDirectory(
                    this, tr("select directory"),
                    "/home/fz", QFileDialog::ShowDirsOnly);
    if(directoryName.isEmpty())
    {
        QMessageBox mesg;
        mesg.warning(this,"警告","打开图片失败!");
        return;
    }
    QStringList fileNameList = getFileNames(directoryName);


    int selectWindow = ui->lwWindow->currentRow();
    if(selectWindow == -1){
        QMessageBox mesg;
        mesg.warning(this,"警告","请选则窗口!");
        return;
    }
    workThread[selectWindow]->setProcessType(getProcessType());
    workThread[selectWindow]->setVideoFile("");
    workThread[selectWindow]->setFileNameList(fileNameList);
    workThread[selectWindow]->setDirectoryName(directoryName);
    workThread[selectWindow]->setImageType(PICTURE);
    workThread[selectWindow]->setThreadName("thread"+ QString::number(selectWindow));

    workThread[selectWindow]->setFlag(true,1);
    workThread[selectWindow]->setFlag(true,2);
    workThread[selectWindow]->setComputingPlatform(getComputingPlatform());
    workThread[selectWindow]->start();
    qDebug()<< "线程"<< selectWindow<<"启动完毕";


}

void MainWindow::on_pbOpenDir_clicked_bak()
{
#ifdef ICE_STATIC_LIBS
    Ice::registerIceSSL();
    Ice::registerIceUDP();
    Ice::registerIceWS();
#endif

    QImage image;
    QString fileFullName;
    QString directoryName = QFileDialog::getExistingDirectory(
                    this, tr("select directory"),
                    "/home/fz", QFileDialog::ShowDirsOnly);
    if(directoryName.isEmpty())
    {
        QMessageBox mesg;
        mesg.warning(this,"警告","打开图片失败!");
        return;
    }
    QStringList fileNameList = getFileNames(directoryName);

    try
    {

         Ice::CommunicatorHolder ich("config.client");
         auto communicator = ich.communicator();

        string ModelPath;
        ModelPath = "../acl_classification/model/mobilenetv2_new.om";
        auto  objIdentify =Ice::uncheckedCast<ObjIdentifyPrx>(communicator->propertyToProxy("Classify.Proxy"));

        if (!objIdentify)
        {
            throw "Invalid proxy";
        }

        objIdentify->SetDevice(deviceID);
        objIdentify->SetModelPath(ModelPath,NULL);
        ::IdentifyModule::AlgorithmInfo algo_info = objIdentify->GetAlgorithmInfo();
        cout << "Contents of GetAlgorithmInfo:" << endl;
        cout << "name=" << algo_info.name << endl;
        cout << "version=" << algo_info.version << endl;

        ::IdentifyModule::Row Img;
        foreach (QString fileName, fileNameList) {
            fileFullName = QString("%1/%2").arg(directoryName).arg(fileName);
            qDebug() << fileFullName;
            ImgToRow(fileFullName.toStdString(), Img);

            ::IdentifyModule::BboxSeq objKind = objIdentify->GetObjBbox(Img);
            cout << "Contents of getObjKinds:" << endl;
            for (int i = 0; i < objKind.size(); i++)
            {
                cout << "name=" << objKind[i].name << endl;
                cout << "confidence=" << objKind[i].confidence << endl;
                cout << "position= ( " << objKind[i].rect.left << "," << objKind[i].rect.top << ",";
                cout << objKind[i].rect.right << "," << objKind[i].rect.bottom << ")" << endl;
            }
        }
    }
    catch(const std::exception& ex)
    {
        cerr << ex.what() << endl;
        return ;
    }
}

QImage MainWindow::cvMat2QImage(const cv::Mat& mat, bool clone, bool rb_swap)
{
    const uchar *pSrc = (const uchar*)mat.data;
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        //QImage image(mat.cols, mat.rows, QImage::Format_Grayscale8);
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        if(clone) return image.copy();
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        if(clone)
        {
            if(rb_swap) return image.rgbSwapped();
            return image.copy();
        }
        else
        {
            if(rb_swap)
            {
                cv::cvtColor(mat, mat, CV_BGR2RGB);
            }
            return image;
        }

    }
    else if(mat.type() == CV_8UC4)
    {
        qDebug() << "CV_8UC4";
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        if(clone) return image.copy();
        return image;
    }
    else
    {
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}
void MainWindow::showResult(QString res ,QString threadName)
{
    qDebug()<< res;
    QImage image;
    QStringList resList = res.split(",");
    QString showMsgVulue;
    Mat frame,src;

    int threadNum = threadName.right(1).toInt();


    if(resList[0] == "detect"){
       int arrayNum =  resList[5].toInt();

       if(resList[1].contains(".mp4")){ // 目标检测 视频
           if(videoFile[threadNum] != resList[1]){
               capture[threadNum].release();
               videoFile[threadNum] = resList[1];
               capture[threadNum].open(resList[1].toLocal8Bit().toStdString());
           }
           capture[threadNum].read(src);
           if(src.empty() || !src.data)
               return;
       }
       else{
           src=imread(resList[1].toUtf8().data());
       }

       Mat dst(416,416,src.type());

       cv::resize(src, dst, dst.size(),0,0,INTER_LINEAR);
       for (int i =0; i<arrayNum;i++) {
            showMsgVulue.append(map[resList[i*5+6]]+"\n");
            int left, top, right, bottom;
            left = resList[i*5+7].toInt();
            top = resList[i*5+8].toInt();
            right = resList[i*5+9].toInt();
            bottom = resList[i*5+10].toInt();
            qDebug()<<  resList[i*5+6]  <<":" <<left<<top<<right<<bottom;
            cv::Rect rect(left,top,right-left,bottom - top);
            rectangle(dst,rect,Scalar(255,0,0),1);
       }
       //https://blog.csdn.net/liyuanbhu/article/details/86307283
       image = cvMat2QImage(dst) ;

       if(threadName == "thread0"){
           showMsg(showMsgVulue,1);
       }else if(threadName == "thread1"){
           showMsg(showMsgVulue,2);
       }else if(threadName == "thread2"){
           showMsg(showMsgVulue,3);
       }else if(threadName == "thread3"){
           showMsg(showMsgVulue,4);
       }

    }else if(resList[0] == "classify"){
        if(threadName == "thread0"){
            showMsg(resList[6],1);
        }else if(threadName == "thread1"){
            showMsg(resList[6],2);
        }else if(threadName == "thread2"){
            showMsg(resList[6],3);
        }else if(threadName == "thread3"){
            showMsg(resList[6],4);
        }

        if(resList[1].contains(".mp4")){
            if(videoFile[threadNum] != resList[1]){
                capture[threadNum].release();
                videoFile[threadNum] = resList[1];
                capture[threadNum].open(resList[1].toLocal8Bit().toStdString());
            }
            capture[threadNum].read(frame);
            if(frame.empty() || !frame.data)
                return;
            cvtColor(frame,frame,CV_BGR2RGB);

            image = QImage((const unsigned char*)(frame.data), frame.cols, frame.rows, QImage::Format_RGB888);

        }else{
            image.load(resList[1]);
            qDebug()<< "image.load(resList[1])  : "<<resList[1];
        }

    }
    // 显示图片
    image = image.scaled(ui->pictureBox->size());
    QPainter painter(&image);
    QPen pen = painter.pen();
    QFont font;
    font.setPixelSize(24);
    pen.setColor(QColor(0,255,128));
    painter.setPen(pen);
    painter.setFont(font);
    painter.drawText(image.rect(),Qt::AlignTop|Qt::AlignLeft,resList[4]+ "ms");
    if(threadName == "thread0"){
        ui->pictureBox->setPixmap(QPixmap::fromImage(image));
        ui->pictureBox->repaint();

    }else if(threadName == "thread1"){
        ui->pictureBox2->setPixmap(QPixmap::fromImage(image));
        ui->pictureBox2->repaint();
    }else if(threadName == "thread2"){
        ui->pictureBox3->setPixmap(QPixmap::fromImage(image));
        ui->pictureBox3->repaint();
    }else if(threadName == "thread3"){
        ui->pictureBox4->setPixmap(QPixmap::fromImage(image));
        ui->pictureBox4->repaint();
    }


    ui->lbAlgorithmInfo->setText(resList[2]);
    ui->lbPlatform->setText(resList[3]);
}

void MainWindow::ImgToRow(string imgfilepath, Row &img_Row)
{
          cv::Mat img = cv::imread(imgfilepath);
          cv::resize(img, img, cv::Size(kModelWidth, kModelHeight));
          int imgSize = kModelWidth * kModelHeight * 3;

          int idxR = 0;
          int idxG = kModelWidth * kModelHeight;
          int idxB = idxG * 2;

          img_Row.resize(imgSize);

          for (int i = 0; i < kModelWidth; ++i)  // rows
          {
                  cv::Vec3b *p = img.ptr<cv::Vec3b>(i);  // ¿i¿
                  char curValue;

                  for (int j = 0; j < kModelHeight; ++j)  // ¿¿¿i¿¿¿¿¿
                  {
                          // ¿¿cell¿¿¿¿¿¿B,G,R
                          curValue = p[j][2];  // R
                         img_Row[idxR++] = curValue;

                          curValue = p[j][1];  // G
                          img_Row[idxG++] = curValue;

                          curValue = p[j][0];  // B
                          img_Row[idxB++] = curValue;
                  }
         }
}




void MainWindow::on_pbStopWorkThread_clicked()
{
    int selectWindow = ui->lwWindow->currentRow();
    if(selectWindow == -1){
        QMessageBox mesg;
        mesg.warning(this,"警告","请选则窗口!");
        return;
    }
    QString threadName;
    switch (selectWindow){
        case 0:
            threadName = "thread0";
            break;
        case 1:
            threadName = "thread1";
            break;
        case 2:
            threadName = "thread2";
            break;
        case 3:
            threadName = "thread3";
            break;
    }
    emit sendFlagToWorkThread(true,2,threadName);
    emit sendFlagToWorkThread(false,1,threadName);
}
void MainWindow::on_pbPauseWorkThread_clicked()
{
    int selectWindow = ui->lwWindow->currentRow();
    if(selectWindow == -1){
        QMessageBox mesg;
        mesg.warning(this,"警告","请选则窗口!");
        return;
    }
    QString threadName;
    switch (selectWindow){
        case 0:
            threadName = "thread0";
            break;
        case 1:
            threadName = "thread1";
            break;
        case 2:
            threadName = "thread2";
            break;
        case 3:
            threadName = "thread3";
            break;
    }

    emit sendFlagToWorkThread(false,2,threadName);
}

void MainWindow::checkrb(bool select)
{

    if(select == false)
        return;
    else{
       ui->rbHandDetect->setChecked(false);
       ui->rbClassify->setChecked(false);
       ui->rbDetection->setChecked(false);

       ui->rbHandDetect->setCheckable(false);
       ui->rbClassify->setCheckable(false);
       ui->rbDetection->setCheckable(false);

       if(ui->rb200dk->isChecked()){
           if(platformFunction["200DK"].contains("手势识别")) {
                ui->rbHandDetect->setCheckable(true);
           }
           if(platformFunction["200DK"].contains("图像分类")){
               ui->rbClassify->setCheckable(true);
           }
           if(platformFunction["200DK"].contains("目标识别")){
               ui->rbDetection->setCheckable(true);
           }

       }else if(ui->rbFpga->isChecked()){
           if(platformFunction["FPGA"].contains("手势识别")) {
                ui->rbHandDetect->setCheckable(true);
           }
           if(platformFunction["FPGA"].contains("图像分类")){
               ui->rbClassify->setCheckable(true);
           }
           if(platformFunction["FPGA"].contains("目标识别")){
               ui->rbDetection->setCheckable(true);
           }

       }else if(ui->rbArm->isChecked()){
           if(platformFunction["ARM"].contains("手势识别")) {
                ui->rbHandDetect->setCheckable(true);
           }
           if(platformFunction["ARM"].contains("图像分类")){
               ui->rbClassify->setCheckable(true);
           }
           if(platformFunction["ARM"].contains("目标识别")){
               ui->rbDetection->setCheckable(true);
           }

       }else if(ui->rbNvidia->isChecked()){
           if(platformFunction["Nvidia"].contains("手势识别")) {
                ui->rbHandDetect->setCheckable(true);
           }
           if(platformFunction["Nvidia"].contains("图像分类")){
               ui->rbClassify->setCheckable(true);
           }
           if(platformFunction["Nvidia"].contains("目标识别")){
               ui->rbDetection->setCheckable(true);
           }

       }
    }
}

void MainWindow::on_pbContinueWorkThread_clicked()
{
    int selectWindow = ui->lwWindow->currentRow();
    if(selectWindow == -1){
        QMessageBox mesg;
        mesg.warning(this,"警告","请选则窗口!");
        return;
    }
    QString threadName;
    switch (selectWindow){
        case 0:
            threadName = "thread0";
            break;
        case 1:
            threadName = "thread1";
            break;
        case 2:
            threadName = "thread2";
            break;
        case 3:
            threadName = "thread3";
            break;
    }
    emit sendFlagToWorkThread(true,2,threadName);
}

void MainWindow::on_OpenVideo_clicked()
{
    QString file = QFileDialog::getOpenFileName(this, "open file dialog","/home/fz/wj-work","mp4 file(*.mp4);;all file(*.*)");
    qDebug()<< file;

//    for(int i=0;i<getThreadNum();i++){
//        workThread[i]->setProcessType(getProcessType());
//        workThread[i]->setVideoFile(file);
//        workThread[i]->setImageType(VIDEO);
//        workThread[i]->clearFileNameList();
//        workThread[i]->setFlag(true,1);
//        workThread[i]->setFlag(true,2);
//        workThread[i]->setComputingPlatform(getComputingPlatform());
//        workThread[i]->setThreadName("thread"+ QString::number(i));
//        workThread[i]->start();
//        qDebug()<< "线程"<< i<<"启动完毕";

//    }

    int selectWindow = ui->lwWindow->currentRow();
    if(selectWindow == -1){
        QMessageBox mesg;
        mesg.warning(this,"警告","请选则窗口!");
        return;
    }
    workThread[selectWindow]->setProcessType(getProcessType());
    workThread[selectWindow]->setVideoFile(file);
    workThread[selectWindow]->setImageType(VIDEO);
    workThread[selectWindow]->clearFileNameList();
    workThread[selectWindow]->setFlag(true,1);
    workThread[selectWindow]->setFlag(true,2);
    workThread[selectWindow]->setComputingPlatform(getComputingPlatform());
    workThread[selectWindow]->setThreadName("thread"+ QString::number(selectWindow));
    workThread[selectWindow]->start();
    qDebug()<< "线程"<< selectWindow<<"启动完毕";
}

cv::Mat MainWindow::QImage2cvMat(QImage &image, bool clone, bool rb_swap)
{
    cv::Mat mat;
    //qDebug() << image.format();
    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void *)image.constBits(), image.bytesPerLine());
        if(clone)  mat = mat.clone();
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void *)image.constBits(), image.bytesPerLine());
        if(clone)  mat = mat.clone();
        if(rb_swap) cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
    case QImage::Format_Grayscale8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine());
        if(clone)  mat = mat.clone();
        break;
    }
    return mat;
}

void MainWindow::readXml(QString xmlPath)
{
    qDebug()<<"readXml..." << "   "<<xmlPath;
    QFile file(xmlPath);
    if(!file.open(QFile::ReadOnly)){
        qDebug()<<"file.open error";
        return;
    }

    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        qDebug()<<"doc.setContent error";
        file.close();
        return;
    }
    file.close();
    QDomElement bookStoreElement=doc.documentElement(); //返回根元素
    qDebug()<<"开始打印xml内容：";
    qDebug()<<bookStoreElement.tagName();
    QDomNodeList bookNodeList=bookStoreElement.childNodes();
    QString key;
    QString value;

    for(int i=0; i<bookNodeList.count(); i++)
    {
        QDomElement bookElement=bookNodeList.at(i).toElement();
        qDebug()<<"  "<<bookElement.tagName()<<" "<<bookElement.attribute("name","");
        key = bookElement.attribute("name","");
        value.clear();
        QDomNodeList childNodeList=bookElement.childNodes();
        for(int j=0; j<childNodeList.count(); j++)
        {
            QDomElement childElement=childNodeList.at(j).toElement();
            qDebug()<<"    "<<childElement.tagName()<<" "<<childElement.text();
            value.append(childElement.text() + "-");
        }
        platformFunction.insert(key, value);
    }
}

void MainWindow::on_pbClearView_clicked()
{
    ui->pictureBox->clear();
    ui->pictureBox2->clear();
    ui->pictureBox3->clear();
    ui->pictureBox4->clear();

}
